package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.utils.JsonUtils;
import com.leyou.dto.PageDTO;
import com.leyou.exception.LyException;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class GoodsServiceImpl implements GoodsService {

    private final SpuService spuService;
    private final SkuService skuService;
    private final SpuDetailService spuDetailService;

    private final BrandService brandService;
    private final CategoryService categoryService;

    private final SpecService specService;


    public GoodsServiceImpl(SpuService spuService,
                            SkuService skuService,
                            SpuDetailService detailService,
                            BrandService brandService,
                            CategoryService categoryService,
                            SpecService specService){

        this.spuService = spuService;
        this.spuDetailService = detailService;
        this.skuService = skuService;

        this.brandService = brandService;
        this.categoryService = categoryService;
        this.specService = specService;


    }

    @Override
    public PageDTO<SpuDTO> PageQuery(Integer page, Integer rows, Long brandId, Long categoryId, Boolean saleable, Long id){

        Page <Spu> iPage = new Page<>(page,rows);

        this.spuService.page(iPage,
                new QueryWrapper<Spu>()
                        .eq(saleable != null, "saleable", saleable)
                        .eq(categoryId != null, "categoryId", categoryId)
                        .eq(brandId != null, "brandId", brandId)
                        .eq(id != null, "id", id)
                        // 3.准备分页条件 LIMIT ?, ?
                        //.page(new Page<>(current, size));

                );

        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(iPage.getRecords());

        spuDTOS.forEach(spuDTO -> {
            String names = this
                    .categoryService
                    .listCategoryByIds(spuDTO.getCategoryIds())
                    .stream()
                    .map(CategoryDTO::getName)
                    .collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
            //TODO获取到的对象一定要保证非空
            spuDTO.setBrandName(this.brandService.findBrandById(spuDTO.getBrandId()).getName());
        });

        return new PageDTO<SpuDTO>(iPage.getTotal(),iPage.getPages(),spuDTOS);
    }

    @Override
    public List<SkuDTO> listSkuBySpu(Long spuId) {


        return SkuDTO.convertEntityList(this.skuService.query().eq("spu_id",spuId).list());
    }

    @Override
    public List<SkuDTO> listSkuByIds(List<Long> ids) {
        return SkuDTO.convertEntityList (this.skuService.listByIds(ids));
    }

    @Override
    public SpuDetailDTO findSpuDetailBySpu(Long spuId) {

        SpuDetail spuDetail = this.spuDetailService.getById(spuId);
        if (null==spuDetail){
            throw new LyException(400,"商品id有误,无所对应的商品信息");
        }

        return new SpuDetailDTO(spuDetail);
    }

    @Override
    public SpuDTO findSpuById(Long id) {
        return new SpuDTO(this.spuService.getById(id));
    }

    @Override
    public SpuDTO findGoodsById(Long id) {

        SpuDTO spuDTO = this.findSpuById(id);

        spuDTO.setSkus(this.listSkuBySpu(id));

        spuDTO.setSpuDetail(this.findSpuDetailBySpu(id));

        return spuDTO;
    }

    @Override
    public List<SpecParamDTO> findSpecParamWithValueBySpu(Long spuId, Boolean searching) {

        Long cid = this.findSpuById(spuId).getCid3();
        if (null==cid){
            throw new LyException(400,"所提供的商品id有误");
        }
        List<SpecParamDTO> specParamDTOS = this.specService.listSpecParams(cid, null, searching);

        //获取到了所有的商品对应的规格参数，需要给规格参数赋值， json==>Map
        //paramMap的key是规格参数的id，specParamId,value是此规格参数的值，类型为Object
         Map<Long,Object> paramMap = JsonUtils.nativeRead(
                this.findSpuDetailBySpu(spuId).getSpecification(),
                new TypeReference<Map<Long, Object>>() {
                });

         specParamDTOS.forEach(specParamDTO -> specParamDTO.setValue(paramMap.get(specParamDTO.getId())));

        return specParamDTOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGoods(SpuDTO spuDTO) {
        Spu spu = spuDTO.toEntity(Spu.class);

        //保存spu并主键回显
        this.spuService.save(spu);

        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        this.spuDetailService.save(spuDetail);

        List<SkuDTO> skusDTOs = spuDTO.getSkus();

        if (CollectionUtils.isEmpty(skusDTOs)){
            throw new LyException(400,"至少应该包含一个sku");
        }

//        List<Sku> skus = new ArrayList<>();
//        skusDTOs.forEach(skuDTO -> {
//            Sku sku = skuDTO.toEntity(Sku.class);
//            sku.setSaleable(true);
//            sku.setSpuId(spu.getId());
//           skus.add(sku) ;
//        });

        List<Sku> skuList = skusDTOs.stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSaleable(true);
            sku.setSpuId(spu.getId());
            return sku;
        }).collect(Collectors.toList());


        this.skuService.saveBatch(skuList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifySaleable(Long id, Boolean saleable) {

        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        //update tb_spu set saleable = #{saleable} where id = #{id}
        this.spuService.updateById(spu);

        Sku sku = new Sku();
        sku.setSaleable(saleable);
        //update tb_sku set saleable = #{saleable} where spu_id = #{spu_id}
        this.skuService.update(sku,new QueryWrapper<Sku>().eq("spu_id",id));
    }


}
